home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d18 / ffind.arc / FFIND.PAS < prev    next >
Pascal/Delphi Source File  |  1991-04-28  |  13KB  |  609 lines

  1. { Copyright (c) 1989 by Chris Thompson  (CompuServe 76367,106) }
  2.  
  3. program FFind;
  4.  
  5. {  Usage:  FFind [d:] [filemask] /switches  }
  6.  
  7. {  note:   FFIND /H will provide a help screen}
  8.  
  9. {$M 32768,0,0}
  10. {A+ Align Data}
  11. {B- Boolean Expressions}
  12. {$I- I/O Checking}
  13. {$R- Range Checking}
  14. {$S- Stack Checking}
  15. {$D- Debug Info}
  16. {$L- Local symbols}
  17. {$N- Emulator}
  18. {$V- Var String Checking}
  19.  
  20. { Note - this program is coded for maximum readability,  }
  21. {        reliability, and maintainability, not           }
  22. {        for fastest possible execution speed.           }
  23.  
  24. {        Screen I/O speed is also limited by maintaining }
  25. {        support for DOS redirection of output.          }
  26.  
  27. { 1.1    first general release }
  28. { 1.2    simplified IntToCommaStr algorithm 2/23/89 }
  29. {        simplified String conversion routines }
  30.  
  31. uses Crt,Dos;
  32.  
  33. const
  34.  
  35.   MonthStr: array[1..12] of string[3] = (
  36.     'Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun',
  37.     'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec');
  38.  
  39.   DayStr: array[0..6] of string[3] =
  40.    ('Sun','Mon','Tue','Wed','Thu','Fri','Sat');
  41.  
  42. type
  43.  
  44.   TargetStr = String[12];
  45.   DriveStr = String;
  46.   Str3 = String[3];
  47.   Str2 = String[2];
  48.  
  49. var
  50.  
  51.   PgmName: String[8];
  52.  
  53.   Prn: Text;
  54.   Con: Text;
  55.  
  56.   FoundCount: Integer;
  57.   TotalBytes: Longint;
  58.   Col : Integer;
  59.  
  60.   LineCount: Byte;
  61.  
  62.   DriveLetter: String;
  63.   TargetFile: TargetStr;
  64.   SaveDir: DirStr;
  65.   DummyDir: DirStr;
  66.   DummyName: NameStr;
  67.   DummyExt: ExtStr;
  68.  
  69.   PauseMode,
  70.   PrintingDirs,
  71.   WideDir : Boolean;
  72.  
  73.   savedExitProc: Pointer;
  74.  
  75.  
  76. procedure FindFiles(Dir:PathStr;Target:TargetStr); forward;
  77.  
  78.  
  79. function UpperCase (InpStr:String) : String;
  80. {Convert a string to Uppercase}
  81. var
  82.   i: integer;
  83. begin
  84.   for i:= 1 to length(InpStr) do
  85.     InpStr[i]:=UpCase(InpStr[i]);
  86.   UpperCase:=InpStr;
  87. end;
  88.  
  89. function LoCase(InChar:char): char;
  90. { convert a Character to lower case }
  91. begin
  92.    if InChar in ['A'..'Z'] then
  93.       LoCase := Chr(ord(InChar)+32)
  94.    else
  95.       LoCase := InChar;
  96. end;
  97.  
  98.  
  99. function LowerCase(InpStr:string):string;
  100. { convert a String to lower case Characters }
  101. var
  102.    i : integer;
  103. begin
  104.    for i := 1 to Length(InpStr) do
  105.      LowerCase[i] := LoCase(InpStr[i]);
  106.    LowerCase[0] := InpStr[0]
  107. end;
  108.  
  109.  
  110. function NumStr(N:longint;D:Integer): String;
  111. {Integer to String with Leading Zeros D places wide}
  112. begin
  113.   NumStr[0] := Chr(D);
  114.   while D > 0 do
  115.     begin
  116.       NumStr[D] := Chr(N mod 10 + Ord('0'));
  117.       N := N div 10;
  118.       Dec(D);
  119.     end;
  120. end;
  121.  
  122. function IntToCommaStr(N:longint): String;
  123. {Comma string from any + or - integer}
  124. const
  125.   s: byte = 0;
  126. var
  127.   W: string[11];
  128.   i: byte;
  129.   d: byte;
  130.  
  131. begin
  132.   Str(N,W);
  133.   if W[1] = '-' then s := 1;
  134.   d := Length(W);
  135.   for i := 3 to (d-1-s) do
  136.     if i mod 3 = 0 then
  137.       Insert(',',W,(d-I+1+s));
  138.   IntToCommaStr := W;
  139. end;
  140.  
  141.  
  142. procedure XHour(HourMil:Integer; var HourCiv :Integer; var ampm : Str2);
  143. begin
  144.   if HourMil > 11 then
  145.     ampm := 'pm'
  146.   else
  147.     ampm := 'am';
  148.  
  149.   Case HourMil of
  150.     0:     HourCiv := 12;
  151.     1..12: HourCiv := HourMil;
  152.     else   HourCiv := HourMil-12;
  153.   end;
  154.  
  155. end;
  156.  
  157.  
  158. procedure FlushKbd;
  159. var
  160.    Ch: Char;
  161. begin
  162.    If KeyPressed then
  163.      repeat
  164.        Ch := ReadKey;
  165.        If Ch =  #0 then Ch := ReadKey;
  166.        If Ch =  #3 then Halt(0);
  167.        If Ch = #27 then Halt(0);
  168.      until (not KeyPressed);
  169. end;
  170.  
  171.  
  172. procedure BackSpace(var f:text;n:longint);
  173. begin
  174.   while n > 0 do
  175.     begin
  176.       Write(Con,#8,' ',#8);
  177.       Dec(n);
  178.     end;
  179. end;
  180.  
  181.  
  182. procedure WaitForKeyPress;
  183. begin
  184.   repeat
  185.   ;
  186.   until KeyPressed;
  187. end;
  188.  
  189.  
  190. function DayNumber(FilDate:DateTime): word;
  191. var
  192.   SysDate:DateTime;
  193.   DayofWeek: word;
  194. begin
  195.   with SysDate do GetDate(Year, Month,Day,DayofWeek);{save system date }
  196.   with FilDate do SetDate(Year,Month,Day);      {set sys date from file}
  197.   with FilDate do GetDate(Year,Month,Day,DayofWeek);{get DoW from sys  }
  198.   with SysDate do SetDate(Year,Month,Day);          {restore sys date  }
  199.   DayNumber := DayofWeek;
  200. end;
  201.  
  202.  
  203. procedure Pause;
  204.  
  205. const
  206.   Msg = 'Program paused; press any key to continue...';
  207.  
  208. begin
  209.   FlushKbd;
  210.   Write(Con,Msg);
  211.   WaitForKeyPress;
  212.   FlushKbd;
  213.   BackSpace(Con,Length(Msg));
  214.   LineCount := 1;
  215. end;
  216.  
  217.  
  218. procedure NewLine(var f:Text);
  219. begin
  220.   WriteLn(f);
  221.   Col := 0;
  222.   If PauseMode then
  223.    begin
  224.      LineCount := LineCount+1;
  225.      If LineCount > 24 then
  226.        Pause;
  227.    end;
  228. end;
  229.  
  230. procedure Beep;
  231. begin
  232.   Sound(880);
  233.   Delay(50);
  234.   NoSound;
  235. end;
  236.  
  237.  
  238. procedure WriteHelp;
  239. begin
  240.    WriteLn(Prn);
  241.    WriteLn(Prn,'Usage: ',PgmName,' [d:] [filespec] [switches] ');
  242.    WriteLn(Prn);
  243.    WriteLn(Prn,'[d:]       is the drive to search; if this is not');
  244.    WriteLn(Prn,'           specified, the default drive is used');
  245.    WriteLn(Prn);
  246.    WriteLn(Prn,'[filespec] is optional; if omitted, *.* is used');
  247.    WriteLn(Prn);
  248.    WriteLn(Prn,'Switches:');
  249.    WriteLn(Prn);
  250.    WriteLn(Prn,'  /W  Wide format');
  251.    WriteLn(Prn,'  /O  Omit directories');
  252.    WriteLn(Prn,'  /P  Pause Mode');
  253.    WriteLn(Prn,'  /H  Help');
  254.    WriteLn(Prn);
  255.    WriteLn(Prn,'Output may be redirected to a file or device, e.g:');
  256.    WriteLn(Prn);
  257.    WriteLn(Prn,'     >LPT1:');
  258.    WriteLn(Prn,'or');
  259.    WriteLn(Prn,'     >fname.ext');
  260.  end;
  261.  
  262.  
  263. {$F+} procedure ProgramExit; {$F-}
  264. begin
  265.     If (errorAddr <> nil) then
  266.      begin
  267.       WriteLn('Program Failed; ExitCode= ',exitcode);
  268.      end
  269.    else if (exitCode <> 0) then
  270.       begin
  271.         WriteLn(Con);
  272.         case ExitCode of
  273.             1: WriteLn(Con,'Invalid FileSpec');
  274.             2: WriteLn(Con,'Invalid Parameter');
  275.         end;
  276.       end;
  277.  
  278.    Close(Prn);
  279.    Close(Con);
  280.  
  281.    exitProc := savedExitProc;
  282. end;
  283.  
  284.  
  285. procedure PrintTotals;
  286. begin
  287.   If Col > 0 then
  288.     NewLine(Prn);
  289.   NewLine(Prn);
  290.   If FoundCount <= 0 then
  291.     begin
  292.       Write(Prn,'no files found');
  293.       NewLine(Prn);
  294.      end;
  295.   NewLine(Prn);
  296.   Write(Prn,'Files found: ',IntToCommaStr(FoundCount));
  297.   NewLine(Prn);
  298.   Write(Prn,'Total bytes: ',IntToCommaStr(TotalBytes));
  299.   NewLine(Prn);
  300.   Write(Prn,'Drive ',DriveLetter,': ',
  301.             'bytes free: ',
  302.              IntToCommaStr(DiskFree(Ord(DriveLetter[1])-64)));
  303.   NewLine(Prn);
  304.   Beep;
  305. end;
  306.  
  307.  
  308. procedure InitPgm;
  309.  
  310. begin
  311.  
  312.   SetCBreak(True);
  313.   CheckBreak := False;
  314.  
  315.   savedExitProc := exitProc;
  316.   exitProc := @ProgramExit;
  317.  
  318.   Assign(Prn,'');
  319.   Rewrite(Prn);
  320.  
  321.   AssignCrt(Con);
  322.   Rewrite(Con);
  323.  
  324.   LineCount := 1;
  325.   FoundCount := 0;
  326.   TotalBytes := 0;
  327.   Col := 0;
  328.   SaveDir := '';
  329.  
  330. end;
  331.  
  332.  
  333. procedure GetCommand;
  334. var
  335.   I: Integer;
  336.   S: PathStr;
  337.   D: DirStr;
  338.   N: NameStr;
  339.   E: ExtStr;
  340.  
  341. begin
  342.   PauseMode := False;
  343.   WideDir := False;
  344.   PrintingDirs := True;
  345.   DriveLetter := '';
  346.   TargetFile := '';
  347.  
  348.   if Lo(DosVersion) >= 3 then
  349.     begin
  350.       FSplit(ParamStr(0), D,N,E);
  351.       PgmName := UpperCase(N);
  352.     end
  353.   else PgmName := 'FFIND';
  354.  
  355.   NewLine(Con);
  356.   Write(Con,PgmName,'-',
  357.               'File Find Ver 1.2 (C) Copyright 1989 C.C. Thompson');
  358.   NewLine(Con);
  359.  
  360.   for I := 1 to ParamCount do
  361.   begin
  362.     S := ParamStr(I);
  363.     if S[1] = '/' then
  364.       begin
  365.         if Length(S) > 1 then
  366.           case UpCase(S[2]) of
  367.             'W': WideDir := True;
  368.             'O': PrintingDirs := False;
  369.             'P': PauseMode := True;
  370.             'H': begin
  371.                    WriteHelp;
  372.                    Halt(0);
  373.                  end;
  374.            else Halt(2);
  375.           end {Case}
  376.        else;
  377.       end  {S[1] = /}
  378.     else   {must either be drive or filespec}
  379.       if ((Length(S) = 2) and (S[2] = ':')) then
  380.          DriveLetter := UpCase(S[1])
  381.       else TargetFile := Copy(S,1,13);
  382.   end;
  383.  
  384.   FlushKbd;
  385.  
  386.   If DriveLetter = '' then
  387.     DriveLetter := Copy(FExpand(''),1,1);
  388.  
  389.   FSplit(TargetFile,DummyDir,N,E);
  390.  
  391.   if N = '' then
  392.     if ((E = '.') or (E = '..')) then
  393.        Halt(1)
  394.     else N := '*';
  395.  
  396.   if E = '' then E := '.*';
  397.  
  398.   TargetFile := N + E;
  399.  
  400.   if DummyDir <> '' then
  401.     begin
  402.       NewLine(Con);
  403.       Write(Con,'The path ',DummyDir, ' is ignored');
  404.       NewLine(Con);
  405.     end;
  406.  
  407.    NewLine(Con);
  408.    Write(Prn,' ':8,'Filespec ', DriveLetter + ':\'+TargetFile,
  409.                    ' used for search');
  410.    NewLine(Prn);
  411.  
  412.  end;
  413.  
  414.  
  415. procedure PrintEntry(Dir:DirStr; FileData:SearchRec);
  416. var
  417.     N: NameStr;
  418.     E: ExtStr;
  419.     T: DateTime;
  420.     ampm: Str2;
  421.     THour: Integer;
  422.     FSize: String;
  423.  
  424. begin
  425.  
  426.   if Col > 4 then
  427.     begin
  428.       NewLine(Prn);
  429.       Col := 0;
  430.     end;
  431.  
  432.   if Dir <> SaveDir then
  433.     begin
  434.       SaveDir := Dir;
  435.       if Col > 0 then
  436.         NewLine(Prn);
  437.       NewLine(Prn);
  438.       Write(Prn,Dir);
  439.       NewLine(Prn);
  440.     end;
  441.  
  442.  
  443.   with FileData do
  444.     begin
  445.  
  446.       if ((Attr and Directory) or (Attr and VolumeID) = 0) then
  447.         Name := LowerCase(Name);
  448.  
  449.       FSplit(Name,DummyDir,N,E);
  450.  
  451.       if (Attr and VolumeID) <> 0 then
  452.         begin
  453.           if Col > 0 then
  454.             NewLine(Prn);
  455.           NewLine(Prn);
  456.           Write(Prn,' ':8,'Volume ',N,' ':6,'created');
  457.           SaveDir := '';
  458.         end
  459.       else
  460.         begin
  461.           if WideDir then
  462.             begin
  463.               Write(Prn,' ':2,N+E, ' ':(13 - Length(N+E)));
  464.               Col := Col + 1;
  465.               Exit;
  466.             end
  467.           else
  468.             begin
  469.               Write(Prn,' ':8,N,E,
  470.                         ' ':(13 - (Length(N)+Length(E))));
  471.               if (Attr and Directory) = 0 then
  472.                 begin
  473.                   FSize := IntToCommaStr((Size));
  474.                   Write(Prn,'':9-Length(FSize),FSize,' bytes  ')
  475.                 end
  476.               else
  477.                 Write(Prn,' ':6,'<DIR>',' ':6);
  478.             end;
  479.         end;
  480.         UnpackTime(Time, T);
  481.         XHour(T.Hour,THour, ampm);
  482.         Write(Prn,
  483.               THour: 4, ':',
  484.               NumStr(T.Min, 2), ' ',
  485.               ampm, '  ',
  486.               DayStr[DayNumber(T)],' ',
  487.               MonthStr[T.Month], ' ',
  488.               T.Day:2,' ',
  489.               NumStr(T.Year mod 100, 2));
  490.         NewLine(Prn);
  491.     end; {with FileData}
  492. end;
  493.  
  494. procedure DosErrorExit;
  495.  
  496. begin
  497.   NewLine(Con);
  498.   case DosError of
  499.           3: Write(Con,'Invalid drive specification ');
  500.    151..163: case DosError of
  501.               152: Write(Con,'Unable to read From drive ',DriveLetter);
  502.               162: Write(Con,'General Failure on drive ',DriveLetter);
  503.               else Write(Con,'Critical Error ',DosError);
  504.             end;
  505.    else Write(Con,'Error ',DosError,' Program terminated abnormally');
  506.   end;
  507.   NewLine(Con);
  508.   Halt;
  509. end;
  510.  
  511.  
  512. procedure FindVolID(Drive:DriveStr);
  513.  
  514. var
  515.   Path: PathStr;
  516.   FoundVol: SearchRec;
  517.  
  518. begin
  519.   if KeyPressed then Pause;
  520.   Path := Drive + ':\'+ '*.';
  521.   FindFirst(Path,VolumeID,FoundVol);
  522.   while (DosError = 0) do
  523.     begin
  524.       if FoundVol.Attr and VolumeID <> 0 then
  525.         begin
  526.           PrintEntry('',FoundVol);
  527.           Exit;
  528.         end;
  529.       if KeyPressed then Pause;
  530.       FindNext(FoundVol);
  531.     end;
  532.     if DosError = 18 then
  533.       begin
  534.         NewLine(Prn);
  535.         Write(Prn,' ':8,'Volume in drive ',DriveLetter,' has no label');
  536.         NewLine(Prn);
  537.       end
  538.     else DosErrorExit;
  539. end;
  540.  
  541.  
  542. procedure SearchCurrent(Dir:PathStr;Target:TargetStr);
  543.  
  544. var
  545.   Path: PathStr;
  546.   FoundFile: SearchRec;
  547.  
  548. begin
  549.   If KeyPressed then Pause;
  550.   Path := Dir + Target;
  551.   FindFirst(Path,
  552.             Hidden + ReadOnly + Directory + Archive + SysFile, FoundFile);
  553.   while (DosError = 0) do
  554.     begin
  555.       if (FoundFile.attr and directory = 0) or PrintingDirs then
  556.         begin
  557.           Inc(FoundCount);
  558.           Inc(TotalBytes, FoundFile.Size);
  559.           PrintEntry(Dir,FoundFile);
  560.         end;
  561.       If KeyPressed then Pause;
  562.       FindNext(FoundFile);
  563.     end; {read loop}
  564.     if DosError <> 18 then DosErrorExit;
  565. end;
  566.  
  567.  
  568. procedure SearchSubDirs(Dir:PathStr;Target:TargetStr);
  569. var
  570.   FoundDir: SearchRec;
  571.   FileSpec: PathStr;
  572.   Path : DirStr;
  573. begin
  574.  If KeyPressed then Pause;
  575.  FileSpec:= Dir + '*.';
  576.  FindFirst(FileSpec, Hidden + ReadOnly + Directory + Archive + SysFile, FoundDir);
  577.  while (DosError = 0) do
  578.    begin
  579.      with FoundDir do
  580.        begin
  581.          If Name[1] <> '.' then
  582.            if Directory and Attr <> 0 then
  583.              begin
  584.                FSplit(FileSpec,Path,DummyName,DummyExt);
  585.                FindFiles(Path + Name + '\' ,Target);
  586.              end;
  587.        end; {with FoundDir}
  588.      if KeyPressed then Pause;
  589.      FindNext(FoundDir);
  590.    end; {read loop}
  591.    If DOSError <> 18 then DosErrorExit;
  592. end;
  593.  
  594. procedure FindFiles(Dir:PathStr;Target:TargetStr);
  595. begin
  596.   SearchCurrent(Dir,Target);
  597.   SearchSubDirs(Dir,Target);
  598. end;
  599.  
  600.  
  601. begin
  602.   InitPgm;
  603.   GetCommand;
  604.   FindVolID(DriveLetter);
  605.   FindFiles(DriveLetter+':\',TargetFile);
  606.   PrintTotals;
  607. end.
  608.  
  609.